原始笔记

3.2 Software Architecture and Design

3.2 Software Architecture and Design(整理版)

原始笔记: Software Design.md 原始教程: 3.2 Software Architecture and Design created: 2026-07-27 10:25 整理说明: 本版本保留原笔记中的设计取舍、架构图、MVC、设计准则与重构建议,仅补充理解这些知识点所需的说明。

内容简要概括

软件设计需要在设计不足与过度设计之间取得平衡,目标不是提前预测所有未来需求,而是为当前问题建立清晰、可测试、易于修改的结构。软件架构可以通过组件与接口图表达系统的高层职责;MVC 等模式提供参考词汇,但最终仍应选择最符合实际使用方式的简单方案。

软件设计、Software Architecture、技术债务、组件、接口、MVCModelViewController、关注点分离、自动化测试、重构

目录


1. 设计的平衡

软件设计需要面对几组现实取舍:

  • 完全不设计,容易积累技术债务;
  • 设计过度,可能把时间浪费在尚未出现的问题上;
  • 需求会变化,初始设计不可能永久正确;
  • 合理目标不是一开始写出完美代码,而是写出当前足够好、易于修改的代码

更稳健的开发策略是:

适度设计
→ 小步实现
→ 自动化测试
→ 持续重构

1.1 技术债务

为了尽快交付而选择容易但受限的方案,可能让软件逐渐变得复杂、难以理解和难以维护。未来修改时付出的额外成本,就是技术债务带来的“利息”。

技术债务不一定能够完全避免,但需要在维护过程中持续偿还,例如简化结构、消除重复、澄清命名和补充测试。

2. 检查项目分支

原笔记保留了用于查看 Git 分支的命令:

git branch --all
  • git branch:列出本地分支;
  • --all:同时显示本地分支和远程跟踪分支。

这条命令只读取分支信息,不会切换或修改分支。

3. Software Architecture

软件架构描述系统的高层结构,包括:

  • 系统有哪些主要组件或模块;
  • 每个组件负责什么;
  • 组件之间如何交互;
  • 系统如何与用户、数据库或外部服务协作。

架构设计可以先用“方框 + 连线”画出结构。图不需要包含所有实现细节,它的作用是帮助团队讨论职责、数据流和接口。

3.1 方框表示组件

每个方框可以代表:

  • 一个代码模块;
  • 一个服务;
  • 用户;
  • 数据库;
  • 外部系统。

例如:

[用户] → [Web 界面] → [分析模块] → [数据库]

这样可以直观看出系统由哪些部分组成,以及每一部分承担什么职责。

3.2 连线表示接口

组件之间的连线可以表示:

  • 数据传递;
  • 函数调用;
  • 控制流程;
  • 网络请求。

例如:

[文件读取模块] ──数据──> [计算模块]

连线不只表示“两个模块有关”,还需要考虑:

  • 传递什么信息;
  • 信息格式是什么;
  • 谁调用谁;
  • 是否需要返回结果。

这些交互约定构成系统的接口。明确接口可以减少组件之间不必要的依赖,使不同组件更容易独立修改和测试。

4. 架构设计练习

4.1 需求

为下面的新功能绘制高层架构:

用户把新的炎症数据上传到一个 Google Drive 文件夹后,软件自动下载数据并更新分析;新结果连同时间戳写入数据库;随后向群组邮件列表发送更新通知。

可以手绘,也可以使用 Excalidraw 等绘图工具。

4.2 原笔记中的解答

![](/assets/attachments/Pasted image 20260727112032.png)

读图约定:

  • 矩形:处理模块或服务;
  • 圆柱体:数据存储;
  • 箭头:调用、触发或数据流;
  • 箭头旁文字:接口、数据或触发方式。

这张图需要表达的核心流程是:

Google Drive 中出现新数据
→ 拉取数据
→ 更新分析
→ 将带时间戳的结果写入数据库
→ 发送邮件通知

绘制这种图时,应重点检查各组件的职责是否明确、数据在哪些边界间流动,以及外部系统失败时会影响哪些步骤。

5. MVC Architecture

Model-View-Controller(MVC)把相关逻辑划分为三个相互协作的部分:

组件 主要职责
Model 管理数据和业务逻辑
View 展示信息并提供用户可见的交互界面
Controller 接收输入,协调 ModelView

5.1 Model

Model 保存和处理应用的数据与核心规则。它不应依赖数据最终如何展示。

5.2 View

View 是用户看到和操作的界面,可以是 GUI,也可以是 CLI 中的文本输出和选项。View 应尽量避免承载复杂业务逻辑。

5.3 Controller

Controller 接收输入并触发相应操作:调用 Model 更新或读取数据,再协调 View 展示结果。

MVC 是架构模式而不是必须严格遵守的规则。实际应用中,ViewController 的边界可能不完全清晰;关键是有意识地分离数据与业务逻辑、展示层和输入协调职责。

6. Architectural Design Guidelines

良好的软件架构不是机械套用规则或模式,而是根据实际问题做出清晰、适度的设计决策:

  • 写代码前与同事讨论设计;
  • 把不同关注点放入不同代码区域;
  • 避免重复代码或重复数据;
  • 尽量减少一个人同时必须理解的信息量;
  • 避免过多抽象;如果阅读代码时需要频繁跳转,可能已经抽象过度;
  • 明确组件之间以及组件与外部系统之间的接口;
  • 不为尚未出现的未来需求设计“永不过时”的方案;
  • 选择能够解决当前问题的最简单方案;
  • 修改结构较差的代码前,先小步重构,使新变化能够自然融入;
  • 离开代码时,让它比接手时更清晰一些。

这些准则共同服务于几个目标:可理解、可修改、可测试和可维护。

7. 通过测试保护重构

7.1 重构前最好有测试

重构要求外部行为保持不变。如果没有测试,很难判断结构调整是否意外改变了结果。

推荐流程:

为现有行为补测试
→ 小步重构
→ 每一步运行测试
→ 确认行为不变

7.2 重构应当小步进行

不建议一次重写整个项目。更可靠的方式是:

改一个名字
→ 运行测试
→ 提取一个函数
→ 运行测试
→ 消除一处重复
→ 运行测试

小步重构有两个直接好处:

  • 出错时容易定位;
  • 每一步都容易审查和回滚。

Switch to English